/* 
 * File:   Camera.cpp
 * Author: brady
 * 
 * Created on February 1, 2011, 3:02 PM
 */

#include "Camera.h"
#include <stdlib.h>

Camera::Camera() {
    SetOrigin(Vector3D(0.0, 0.0, 0.0));
    SetGaze(Vector3D(0.0, 0.0, 1.0));
    this->SetFocalLength(1.0);
    this->SetFrameWidth(4.0);
    this->SetResolution(400.0, 300.0);
    this->SetAspectRatio(4.0/3.0);
}

Camera::Camera(Vector3D origin, Vector3D gaze)
{
    SetOrigin(origin);
    SetGaze(gaze);
    SetFocalLength(2.0);
    SetFrameWidth(4.0);
    SetResolution(400.0, 300.0);
    SetAspectRatio(4.0/3.0);
}

Camera::Camera(const Camera& orig) {
    this->FocalLength = orig.FocalLength;
    this->FrameHeight = orig.FrameHeight;
    this->Gaze = orig.Gaze;
    this->Origin = orig.Origin;
    this->ResolutionX = orig.ResolutionX;
    this->ResolutionY = orig.ResolutionY;
    this->U = orig.U;
    this->V = orig.V;
    this->W = orig.W;
}

Camera::~Camera() {
}

void Camera::SetOrigin(Vector3D origin)
{
    Origin = origin;
    BuildBasis();
}

void Camera::SetGaze(Vector3D gaze)
{
    gaze.normalize();
    Gaze = gaze;
    BuildBasis();
}

void Camera::SetFocalLength(double length)
{
    FocalLength = length;
}
void Camera::SetFrameWidth(double width)
{
    FrameWidth = width;
}
void Camera::SetResolution(int Xres, int Yres)
{
    ResolutionX = Xres;
    ResolutionY = Yres;
}

void Camera::BuildBasis()
{
    Vector3D up = Vector3D(0.0, 1.0, 0.0);
    W = Gaze * -1.0;
    U = up.cross(W);
    U.normalize();
    V = W.cross(U);
    V.normalize();
}

Ray Camera::ComputeRay(int row, int col, int spp, int sampleNum)
{
    double left, right, top, bottom;
    left = -GetFrameWidth()/2;
    right = GetFrameWidth()/2;
    top = -GetFrameHeight()/2;
    bottom = GetFrameHeight()/2;
    double directionX, directionY, directionZ;
    double sampleXOffset, sampleYOffset;

    if(sampleNum < 0)
    {
        sampleXOffset = (sampleNum % 2 == 0)? 0.0 : 1.0;
        sampleYOffset = (sampleNum <= -3)? 0.0 : 1.0;
        if(sampleNum == -5)
        {
            sampleXOffset = 0.5;
            sampleYOffset = 0.5;
        }

    }
    else{
        int sampleRows = sqrt(spp);
        int sampleCols = sampleRows;
        double rMult = ((double)random()/(double)RAND_MAX)*2.0;
        if(spp == 1) rMult = 1.0;//between 0 and 2.0
        sampleXOffset = (1.0/(sampleCols*2.0))*rMult;
        rMult = ((double)random()/(double)RAND_MAX)*2.0;
        if(spp == 1) rMult = 1.0;
        sampleYOffset = (1.0/(sampleRows*2.0))*rMult;


        int sampleColumn = sampleNum % sampleCols;
        int sampleRow = sampleNum / sampleRows;

        sampleXOffset += (double)sampleColumn/(double)sampleCols;
        sampleYOffset += (double)sampleRow/(double)sampleRows;
    }

    directionX = left + GetFrameWidth()*((col + sampleXOffset)/ResolutionX);
    directionY = top + GetFrameHeight()*((row + sampleYOffset)/ResolutionY);
    directionZ = FocalLength;
    Vector3D dir;
    dir = U*directionX + V*directionY + W*-1.0*directionZ;
    dir.normalize();
    Ray r = Ray(Origin, dir);
    r.sNum = sampleNum;
    return r;

}